package vip.liux.contracts.security;

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.UserDetailsManager;
import vip.liux.contracts.models.identity.IdentityRole;
import vip.liux.contracts.models.identity.IdentityUser;
import vip.liux.contracts.models.identity.IdentityUserLoginId;
import vip.liux.contracts.models.identity.UserDomainManager;
import vip.liux.contracts.models.identity.vo.UserLoginInfo;

import java.time.Instant;
import java.util.Locale;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 用户详细信息管理适配器
 * <p>实现了 {@link UserDetailsManager} 接口，用于管理用户的创建、更新、删除等操作。</p>
 */
public class UserDetailsManagerAdapter implements UserDetailsManager {
    public static Supplier<UserDetailsManager> SUPPLIER;

    public static final String DEFAULT_PASSWORD = "123@Abcd";
    protected final UserDomainManager userDomainManager;
    protected final PasswordEncoder passwordEncoder;

    /**
     * 构造方法
     *
     * @param userDomainManager 用户领域管理器
     * @param passwordEncoder   密码加密器
     */
    public UserDetailsManagerAdapter(UserDomainManager userDomainManager, PasswordEncoder passwordEncoder) {
        this.userDomainManager = userDomainManager;
        this.passwordEncoder = passwordEncoder;
    }

    /**
     * 根据用户名加载用户信息
     *
     * @param account 用户名或账户标识
     * @return 用户详细信息
     * @throws UsernameNotFoundException 如果用户不存在
     */
    @Override
    public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
        IdentityUser accountUser = findByAccount(account)
                .orElseThrow(() -> new UsernameNotFoundException("用户未找到"));
        return UserConverter.toUserInfo(accountUser);
    }

    /**
     * 创建用户
     *
     * @param user 用户详细信息
     */
    @Override
    public void createUser(UserDetails user) {
        String encodedPassword = passwordEncoder.encode(StringUtils.isBlank(user.getPassword()) ? DEFAULT_PASSWORD : user.getPassword());
        IdentityUser accountUser = UserConverter.toIdentityUser(user, DEFAULT_PASSWORD, encodedPassword);
        IdentityUser identityUser = userDomainManager.createUser(accountUser);
    }

    /**
     * 更新用户信息
     *
     * @param user 用户详细信息
     */
    @Override
    public void updateUser(UserDetails user) {
        IdentityUser accountUser = userDomainManager.findByUsername(user.getUsername());
        if (accountUser == null) {
            throw new UsernameNotFoundException("用户未找到");
        }
        accountUser.setPasswordHash(passwordEncoder.encode(user.getPassword()));
        accountUser.setActive(user.isEnabled());
        IdentityUser identityUser = userDomainManager.updateUser(accountUser);
    }

    /**
     * 删除用户
     *
     * @param account 用户名或账户标识
     */
    @Override
    public void deleteUser(String account) {
        IdentityUser accountUser = findByAccount(account)
                .orElseThrow(() -> new UsernameNotFoundException("用户未找到"));
        userDomainManager.deleteUser(accountUser);
    }

    /**
     * 更改用户密码
     *
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     */
    @Override
    public void changePassword(String oldPassword, String newPassword) {
        IdentityUser currentUser = findByAccount(getCurrentUsername())
                .orElseThrow(() -> new UsernameNotFoundException("用户未找到"));
        if (!passwordEncoder.matches(oldPassword, currentUser.getPasswordHash())) {
            throw new IllegalArgumentException("旧密码不正确");
        }
        currentUser.setPasswordHash(passwordEncoder.encode(newPassword));
        userDomainManager.changePassword(currentUser, oldPassword, newPassword);
    }

    /**
     * 检查用户是否存在
     *
     * @param username 用户名
     * @return 如果用户存在返回 true，否则返回 false
     */
    @Override
    public boolean userExists(String username) {
        return findByAccount(username).isPresent();
    }

    /**
     * 根据账户标识查找用户
     *
     * @param account 用户名、邮箱或 ID
     * @return 用户信息的 Optional 对象
     */
    public Optional<IdentityUser> findByAccount(String account) {
        return Optional.ofNullable(userDomainManager.findByUsername(account))
                .or(() -> Optional.ofNullable(userDomainManager.findByEmail(account)))
                .or(() -> Optional.ofNullable(userDomainManager.findByPhoneNumber(account)));
    }

    /**
     * 获取当前登录用户的用户名
     *
     * @return 当前用户名
     */
    private String getCurrentUsername() {
        return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
                .map(Authentication::getName)
                .orElseThrow(() -> new IllegalStateException("未找到认证用户"));
    }

    /**
     * 用户转换工具类
     */
    public static class UserConverter {

        /**
         * 将 UserDetails 转换为 IdentityUser
         *
         * @param user            用户详细信息
         * @param defaultPassword 默认密码
         * @param encodedPassword 加密后的密码
         * @return IdentityUser 对象
         */
        public static IdentityUser toIdentityUser(UserDetails user, String defaultPassword, String encodedPassword) {
            IdentityUser accountUser = new IdentityUser();
            accountUser.setUsername(user.getUsername());
            accountUser.setNormalizedUserName(user.getUsername().toUpperCase(Locale.ROOT));
            accountUser.setPhoneNumber(user.getUsername());
            accountUser.setPasswordHash(encodedPassword);
            accountUser.setEmail(user.getUsername() + "@liux.vip");
            accountUser.setNormalizedEmail(user.getUsername() + "@liux.vip".toUpperCase(Locale.ROOT));
            accountUser.setActive(user.isEnabled());
            accountUser.setLockoutEnabled(true);
            return accountUser;
        }

        /**
         * 将 IdentityUser 转换为 UserInfo
         *
         * @param accountUser IdentityUser 对象
         * @return UserInfo 对象
         */
        public static UserInfo toUserInfo(IdentityUser accountUser) {
            UserInfo info = new UserInfo(
                    Optional.ofNullable(accountUser.getId()).map(Object::toString).orElse(null),
                    accountUser.getName(),
                    accountUser.getSurname(),
                    accountUser.getPhoneNumber(),
                    accountUser.getEmail(),
                    accountUser.isPhoneNumberConfirmed(),
                    accountUser.isEmailConfirmed(),
                    accountUser.getRoles().stream()
                            .filter(IdentityRole::isPublic)
                            .map(IdentityRole::getDisplayName)
                            .collect(Collectors.toSet()),
                    accountUser.getUsername(),
                    accountUser.getPasswordHash(),
                    accountUser.isActive(),
                    accountUser.getLockoutEnd() == null || accountUser.getLockoutEnd().isAfter(Instant.now()),
                    accountUser.getRoles().stream()
                            .map(role -> (GrantedAuthority) role::getName)
                            .collect(Collectors.toList())
            );
            if (!accountUser.getLogins().isEmpty()) {
                info.getAttributes().put("logins", accountUser.getLogins().stream().map(s ->
                        new UserLoginInfo(Optional.ofNullable(s.getId()).map(IdentityUserLoginId::getLoginProvider).orElseThrow(), s.getProviderKey(), s.getProviderDisplayName())
                ).toList());
            }
            if (!accountUser.getRoles().isEmpty()) {
                info.getAttributes().put("roles", accountUser.getRoles().stream().map(IdentityRole::getName).toList());
            }
            return info;
        }
    }
}